import { IVec2 } from "../../util/Defined";
import { TypeUtil } from "../../util/TypeUtil";
import { Intersection } from "../Intersection";
import { Matrix } from "../math/Matrix";
import { Vec2 } from "../math/Vec2";
import { BaseShape, ShapeType } from "./BaseShape";
import { BoxShape } from "./BoxShape";
import { CircleShape } from "./CircleShape";

/**
 * 多边形图形
 */
export class PolygonShape extends BaseShape {

    protected _worldPolygon: Vec2[] = [];
    get worldPolygon(): readonly Vec2[] {
        return this._worldPolygon;
    }

    protected _polygon: Vec2[] = [];
    get polygon(): readonly Vec2[] {
        return this._polygon;
    }

    /**
     * 设置多边形
     * @param polygon 多边形顶点列表
     */
    setPolygon(polygon: readonly Readonly<IVec2>[]) {
        if (this._polygon.length > polygon.length) {
            this._polygon.length = polygon.length;
        }
        for (let i = 0; i < polygon.length; ++i) {
            if (this._polygon[i]) {
                this._polygon[i].setPosTo(polygon[i]);
            } else {
                this._polygon[i] = new Vec2(polygon[i].x, polygon[i].y);
            }
        }
        if (this._worldPolygon.length >= polygon.length) {
            this._worldPolygon.length = polygon.length;
        } else {
            for (let count = polygon.length - this._worldPolygon.length; --count >= 0;) {
                this._worldPolygon.push(new Vec2());
            }
        }
        return this;
    }

    getType(): ShapeType {
        return ShapeType.polygon;
    }

    update(pos: Readonly<IVec2>, trans?: Readonly<Matrix>): this {
        let minX = 1e6, minY = 1e6, maxX = -1e6, maxY = -1e6;
        for (let i = 0; i < this.polygon.length; ++i) {
            const lPos = this._polygon[i];
            const wPos = this._worldPolygon[i];

            wPos.setPosTo(lPos).addPosTo(this);
            trans?.transformPointN(wPos);
            wPos.addPosTo(pos);

            if (wPos.x > maxX) maxX = wPos.x;
            if (wPos.x < minX) minX = wPos.x;
            if (wPos.y > maxY) maxY = wPos.y;
            if (wPos.y < minY) minY = wPos.y;
        }

        this.worldAABB.setRect(
            minX,
            minY,
            maxX - minX,
            maxY - minY
        );

        return this;
    }

    testCollide(shape: Readonly<BaseShape>): boolean {
        if (!Intersection.rectRect(this.worldAABB, shape.worldAABB)) {
            return false;
        }

        switch (shape.getType()) {
            case ShapeType.circle:
                return Intersection.polygonCircle2(this.worldPolygon, (shape as CircleShape).worldCircle);
            case ShapeType.rect:
                return Intersection.rectPolygon(shape.worldAABB, this.worldPolygon);
            case ShapeType.box:
            case ShapeType.polygon:
                return Intersection.polygonPolygon(this.worldPolygon, (shape as BoxShape | PolygonShape).worldPolygon);
        }

        throw new Error(`未实现碰撞方法：${TypeUtil.getCls(this).name} -> ${TypeUtil.getCls(shape).name}`);
    }

}